-- 工具文件
-- 2021.05.08
-- Lingd
-- 福州泰诚网络科技有限公司

module(...,package.seeall)

require "tool"
require "usart"

RA           	= 0x0000        -- 广播命令
RD           	= 0x0100        -- 读命令
WR           	= 0x0200        -- 写命令
	
ID_1         	= 0x0000        -- 第1-2路地址
ID_2         	= 0x0400        -- 第3-4路地址
ID_3         	= 0x0800        -- 第5-6路地址
ID_4         	= 0x0C00        -- 第7-8路地址
	
REG_SYSCTRL  	= 0x1080        -- 系统控制寄存器
REG_PAC      	= 0x00F6        -- A通道有功功率比差校正
REG_PHC      	= 0x00F7        -- 有功功率角差校正
REG_PADCC    	= 0x00F8        -- A通道有功功率小信号校正
REG_QAC      	= 0x00F9        -- A路无功功率比差校正
REG_QBC      	= 0x00FA        -- B路无功功率比差校正
REG_QADCC    	= 0x00FB        -- A无功功率小信号校正
REG_QBDCC    	= 0x00FC        -- B无功功率小信号校正
REG_IAC      	= 0x00FD        -- A路电流有效值比差校正
REG_IADCC    	= 0x00FE        -- A路电流有效值小信号校正
REG_UC       	= 0x00FF        -- 电压有效值比差校正
REG_PBC      	= 0x1000        -- B路有功功率比差校正
REG_PBDCC    	= 0x1001        -- B路有功功率小信号校正
REG_IBC      	= 0x1002        -- B路电流有效值比差校正
REG_IBDCC    	= 0x1003        -- B路电流有效值小信号校正
REG_IAADCC   	= 0x1004        -- A路电流ADC直流偏置校正
REG_IBADCC   	= 0x1005        -- B路电路ADC直流偏置校正
REG_UADCC    	= 0x1006        -- 电压ADC直流偏置校正
REG_BPFPARA  	= 0x1007        -- 带通滤波器系数
REG_UDCC     	= 0x1008        -- 电压有效值小信号校正
REG_CKSUM    	= 0x1009        -- 校验和寄存器
REG_RSTSRC      = 0x00CA        -- 复位原因标志位寄存器
REG_SFTRST   	= 0x10BF        -- 软件复位寄存器
REG_SYSSTS   	= 0x00CA        -- 系统状态寄存器
REG_FREQINST 	= 0x00CB        -- 瞬时频率值
REG_PAINST   	= 0x00CC        -- A路瞬时有功功率值
REG_QINST    	= 0x00CD        -- 瞬时无功功率值
REG_IAINST   	= 0x00CE        -- A路瞬时电流有效值
REG_UINST    	= 0x00CF        -- 瞬时电压有效值
REG_PAAVG    	= 0x00D0        -- A路平均有功功率值
REG_QAVG     	= 0x00D1        -- 平均无功功率值
REG_FREQAVG  	= 0x00D2        -- 平均频率值
REG_IAAVG    	= 0x00D3        -- A路平均电流有效值
REG_UAVG     	= 0x00D4        -- 平均电压有效值
REG_PBINST   	= 0x00D5        -- B路瞬时有功功率值
REG_IBINST   	= 0x00D6        -- B路瞬时电流有效值
REG_PBAVG    	= 0x00D7        -- B路平均有功功率值
REG_IBAVG    	= 0x00D8        -- B路平均电流有效值
REG_UDCINST  	= 0x00D9        -- 电压瞬时直流分量值
REG_IADCINST 	= 0x00DA        -- A路瞬时直流分量值
REG_IBDCINST 	= 0x00DB        -- B路瞬时直流分量值
REG_ZXDATREG 	= 0x00DC        -- 电压过零点前一次采样值
REG_ZXDAT    	= 0x00DD        -- 电压过零点当前点采样值
REG_PHDAT    	= 0x00DE        -- 电压相位数据
REG_T8BAUD   	= 0x00E0        -- 当前波特率

SlotTime        = 100            -- 采集间隔（单位：ms）
SendRegStep     = {{ID_1,REG_UC},{ID_1,REG_IBC},{ID_1,REG_IAC},{ID_2,REG_IBC},{ID_2,REG_IAC},{ID_3,REG_IBC},{ID_3,REG_IAC},{ID_4,REG_IBC},{ID_4,REG_IAC},}                      -- 设置寄存器顺序
ReadRegStep     = {{ID_1,REG_UAVG},{ID_1,REG_IBAVG},{ID_1,REG_IAAVG},{ID_2,REG_IBAVG},{ID_2,REG_IAAVG},{ID_3,REG_IBAVG},{ID_3,REG_IAAVG},{ID_4,REG_IBAVG},{ID_4,REG_IAAVG}}     -- 设置寄存器顺序
Urms            = 0             -- 电压有效值（单位：0.0V）
Irms            = {0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000}     -- 电流有效值（单位：0.000A）

local SendAddr  = 0             -- 当前操作的芯片地址
local SendReg   = 0             -- 当前操作的寄存器芯片地址

-- 计算校验和（专用）
function calcSum(Data,Pos,Len)
    local i,num = 0,0

    if #Data < Pos+Len-1 then
        return 0
    end

    for i = 0,Len-1 do
        num = num + Data[Pos+i]
    end
    num = bit.band(num,0x000000ff)
    
    return bit.band(bit.band(bit.bnot(num),0x000000ff) + 0x33,0x000000ff)
end

-- 计量芯片协议组包
function pack(addr,reg,cmd,data)
    local buf = {}

    SendAddr= bit.band(bit.rshift(addr,10),0x0003)    -- 记录芯片地址
    SendReg = reg                   -- 记录寄存器
    reg = bit.bor(reg,bit.bor(cmd,addr))

    buf[1] = 0x7D                   -- 包头
    buf[2] = reg/256                -- 控制字节
    buf[3] = reg%256                -- 地址字节
    buf[4] = data[1]                -- 数据0
    buf[5] = data[2]                -- 数据1
    buf[6] = data[3]                -- 数据2
    buf[7] = data[4]                -- 数据3
    buf[8] = calcSum(buf,1,#buf)    -- 校验字节

    --log.info("send data",tool.HextoHexStr(buf," "))
    usart.write(buf)                -- 发送数据
end

-- 计量芯片寄存器解析
function cmd_unpack(data)
    -- 电压有效值
    if SendReg == REG_UAVG then
        local UrmsHex = bit.lshift(data[4],24) + bit.lshift(data[3],16) + bit.lshift(data[2],8) + data[1]
        local Meu_Urms = UrmsHex / 919495302.0 / 4.0
        --log.info("Urms:",string.format("%5.2fV",Meu_Urms * 1000))
        Urms = Meu_Urms * 1000
    -- B路电流有效值
    elseif SendReg == REG_IBAVG then
        local IrmsHex = bit.lshift(data[4],24) + bit.lshift(data[3],16) + bit.lshift(data[2],8) + data[1]
        local Meu_Irms = IrmsHex / 919495302.0 / 4.0
        --log.info("IBrms","第"..(SendAddr*2+1).."路")
        Irms[(SendAddr*2+1)] = (Meu_Irms / 5) * 1000
    -- A路电流有效值
    elseif SendReg == REG_IAAVG then
        local IrmsHex = bit.lshift(data[4],24) + bit.lshift(data[3],16) + bit.lshift(data[2],8) + data[1]
        local Meu_Irms = IrmsHex / 919495302.0 / 4.0
        --log.info("IArms","第"..(SendAddr*2+2).."路")
        Irms[(SendAddr*2+2)] = (Meu_Irms / 5) * 1000

        --if (SendAddr*2+2) == 8 then
            --log.info("Irms",string.format("%5.3fA %5.3fA %5.3fA %5.3fA %5.3fA %5.3fA %5.3fA %5.3fA",Irms[1],Irms[2],Irms[3],Irms[4],Irms[5],Irms[6],Irms[7],Irms[8]))
        --end
    -- B路电流校准值
    elseif SendReg == REG_IBC then
        log.info("IBC","第"..(SendAddr*2+1).."路")
    -- A路电流校准值
    elseif SendReg == REG_IAC then
        log.info("IAC","第"..(SendAddr*2+2).."路")
    elseif SendReg == REG_UC then
        log.info("REG_UC",tool.HextoHexStr(data," "))
    elseif SendReg == REG_RSTSRC then
        log.info("REG_RSTSRC",tool.HextoHexStr(data," "))
    else
        log.info("none reg")
    end
end

-- 计量芯片协议解包
function unpack(pbuf)
    local i,j,pos,len,ret,data = 1,1,1,0,false,{}
    
    -- 配置回应包
    if #pbuf < 8 then
        -- 收到4个字节，尝试进行校验，是否为设置命令回应
        if #pbuf ~= 4 then
            --log.info("len error")
            ret = false
        else
            if pbuf[1] ~= 0x7D then                                 -- 找到包头（0x7D）
                --log.info("not head")
                ret = false
            else
                if calcSum(pbuf,1,3) ~= pbuf[4] then                -- 进行数据校验
                    --log.info("check error")                         -- 校验错误
                    ret = false
                else
                    if SendReg == bit.band(bit.bor(bit.lshift(pbuf[2],8),pbuf[3]),0x0000f0ff) then
                        --log.info("reg ack ok")
                        ret = true
                    else
                        ret = false
                    end
                end
            end
        end
    end

    -- 读取回应包
    while (pos < #pbuf) and (#pbuf - 8 >= 0) do    
        -- 0x7D查找协议头
        for i = 1,#pbuf do
            if pbuf[pos] == 0x7D then                   -- 找到包头（0x7D），则往下执行
                pos = pos + 1                           -- 指向MCU地址   
                pos = pos + 1                           -- 指向数据长度N*4 
				if pos > #pbuf	then return false end	-- 包错误
                len = pbuf[pos] * 4                     -- 获取长度
                pos = pos + 1                           -- 指向数据区

                if calcSum(pbuf,pos-3,3+len) ~= pbuf[pos+len] then
                    log.info("check error")             -- 校验错误
                    ret = false
                    break
                end

                for j = 1,len do
                    data[j] = pbuf[pos+j-1]
                end

                cmd_unpack(data)                        -- 命令解析
                pos = pos + len + 1                     -- 指向下一个包
                
                ret = true

                if pos >= #pbuf then                    -- 是否已到包尾
                    break
                end
            else
                pos = pos + 1                           -- 指向下一个字节
            end
        end
    end
    return ret
end

-- 计算电压校准值
function CalcCaliU(Val)
	local Eu = (Urms - Val) / Val
	local S = math.pow(2, 31) * (1 / (1 + Eu) - 1) + Urms * (1 / (1 + Eu))
	local data = {}
	data[1] = bit.band(S,0x000000ff)
	data[2] = bit.band(bit.rshift(S,8),0x000000ff)
	data[3] = bit.band(bit.rshift(S,16),0x000000ff)
	data[4] = bit.band(bit.rshift(S,24),0x000000ff)
	
	return data
end

-- 计算电流校准值
function CalcCaliI(Ch,Val)
	local Eu = (Irms[Ch] - Val) / Val
	local S = math.pow(2, 31) * (1 / (1 + Eu) - 1) + Irms[Ch] * (1 / (1 + Eu))
	local data = {}
	data[1] = bit.band(S,0x000000ff)
	data[2] = bit.band(bit.rshift(S,8),0x000000ff)
	data[3] = bit.band(bit.rshift(S,16),0x000000ff)
	data[4] = bit.band(bit.rshift(S,24),0x000000ff)
	
	return data
end
